package com.xcity.game.treasurebox;

import java.util.List;
import java.util.Random;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.xcity.db.entity.Build;
import com.xcity.db.entity.Player;
import com.xcity.game.build.BuildIncomeCause;
import com.xcity.game.common.Cause;
import com.xcity.game.common.GameStaticConfig;
import com.xcity.game.common.MessageConst;
import com.xcity.game.common.PlayerPool;
import com.xcity.game.event.GameEvents;
import com.xcity.game.item.ItemException;
import com.xcity.game.item.ItemInfo;
import com.xcity.pomelo.PomeloRoute;
import com.xcity.pomelo.push.msg.TreasureBoxPush;
import com.xcity.pomelo.request.OpenTreasureBoxRequest;
import com.xcity.pomelo.response.HintResponse;
import com.xcity.pomelo.response.OpenTreasureBoxResponse;
import com.xcity.pomelo.response.Response;

import naga.x.App;
import naga.x.event.Event;
import naga.x.event.EventListener;
import naga.x.game.template.TemplateService;
import naga.x.game.time.TimeUpdater;
import naga.x.net.Session;
import naga.x.net.annotation.OPHandler;
import naga.x.net.impl.pomelo.annotation.PomeloOP;
import naga.x.service.Service;
import naga.x.service.ServiceException;
import naga.x.util.CommonUtils;

/**
 * 宝箱系统
 * @author yang.li
 *
 */
@OPHandler
public class TreasureBoxService implements Service, EventListener, PlayerPool {

	public static final int DROP_BOX_CD = 60 * 60 * 1000; // 掉落cd 1小时
	private static final Logger LOG = LoggerFactory.getLogger(TreasureBoxService.class);
	
	private List<TreasureBoxTemplate> templates;
	private int totalWeight;
	private static final Random RND = new Random();
	
	@Override
	public void startup() throws ServiceException {
		templates = App.getApp().getServiceManager().get(TemplateService.class).getTemplatesList(TreasureBoxTemplate.class);
		int weight = 0;
		for (TreasureBoxTemplate temp : templates) {
			temp.setWeight(weight += temp.getWeight());
		}
		totalWeight = weight;
		App.getApp().getEventManager().register(this);
	}

	@Override
	public void shutdown() throws ServiceException {
	}

	@Override
	public String getId() {
		return "TREASURE BOX";
	}

	@Override
	public int[] getEventTypes() {
		return new int[] {
				GameEvents.EVENT_TAKE_MONEY_IN_BUILD,
				GameEvents.EVENT_PLAYER_LOGIN,
				GameEvents.EVENT_PLAY_PET,
				GameEvents.EVENT_WASH_PET
				};
	}

	@Override
	public void handleEvent(Event event) {
		switch (event.getType()) {
			case GameEvents.EVENT_TAKE_MONEY_IN_BUILD:
				tryTriggerDrop(event.getParameter(0), event.getParameter(1), event.getParameter(2), event.getParameter(3));
				break;
			case GameEvents.EVENT_PLAY_PET: // 30%几率掉
				dropBox(event.getParameter(), 3000, Cause.PET_PLAY);
				break;
			case GameEvents.EVENT_WASH_PET: // 必掉
				dropBox(event.getParameter(), GameStaticConfig.defaultChanceBase, Cause.PET_WASH);
				break;
		}
	}
	
	private void tryTriggerDrop(Player player, Build build, int moneyGot, BuildIncomeCause cause) {
		if (cause == BuildIncomeCause.MANUAL) {
			TreasureBoxState state = player.getPool().getObject(PROPERTY_TREASURE_BOX_STATE, TreasureBoxState.class);
			if ((state == null || state == TreasureBoxState.RECEIVED)
					&& (TimeUpdater.getInstance().now() - player.getPool().getLongValue(PROPERTY_LAST_DROP_TREASURE_BOX_TIME)) > DROP_BOX_CD
					&& GameStaticConfig.triggerTreasureBoxDrop(RND, moneyGot * 100 / /*temp.getMaxIncome()*/build.getMaxIncome())
					) {
				// trigger drop
				player.poolSet(PROPERTY_TREASURE_BOX_STATE, TreasureBoxState.INITED);
				player.poolSet(PROPERTY_LAST_DROP_TREASURE_BOX_TIME, TimeUpdater.getInstance().now());
				player.send(TreasureBoxPush.DEFAULT);
				LOG.info("[TREASURE BOX GET]ID[{}]CAUSE[BUILDINCOME]", player.getId());
			}
		}
	}
	
	private void dropBox(Player player, int probability, String cause) {
		TreasureBoxState state = player.getPool().getObject(PROPERTY_TREASURE_BOX_STATE, TreasureBoxState.class);
		if (state == TreasureBoxState.INITED) {
			return;
		}
		int n = RND.nextInt(GameStaticConfig.defaultChanceBase);
		if (n < probability) {
			player.poolSet(PROPERTY_TREASURE_BOX_STATE, TreasureBoxState.INITED);
			player.send(TreasureBoxPush.PET_OP);
			LOG.info("[TREASURE BOX GET]ID[{}]CAUSE[{}]", player.getId(), cause);
		}
	}
	
	@PomeloOP(PomeloRoute.OPEN_TREASURE_BOX)
	protected void requestOpenBox(Session session, OpenTreasureBoxRequest req) {
		Player player = session.getClient();
		TreasureBoxState state = player.getPool().getObject(PROPERTY_TREASURE_BOX_STATE, TreasureBoxState.class);
		if (state == null) {
//			session.send(new HintResponse(req.getSerial(), MessageConst.HAVE_NO_TREASURE_BOX));
			session.send(new Response(req.getSerial()));
			return;
		}
		player.poolRemove(PROPERTY_TREASURE_BOX_STATE);
		ItemInfo item = openBox();
		if (item == null) {
			session.send(new HintResponse(req.getSerial(), MessageConst.SYSTEM_ERROR));
			LOG.info("[TREASURE BOX ERROR]ID[{}]", player.getId());
			return;
		}
		try {
			player.getBag().addItem(item.getId(), item.getCount(), Cause.TREASURE_BOX);
			session.send(new OpenTreasureBoxResponse(req.getSerial(), item));
			LOG.info("[TREASURE BOX OPEN]ID[{}]ITEM[{}={}]", player.getId(), item.getId(), item.getCount());
		} catch (ItemException e) {
			LOG.error("[TREASURE BOX ERROR]ID[" + player.getId() + "]ITEM[" + item.getId() + "=" + item.getCount() + "]", e);
			session.send(new HintResponse(req.getSerial(), e.getMessage()));
		}
	}
	
	private ItemInfo openBox() {
		int n = CommonUtils.randomInt(totalWeight);
		for (TreasureBoxTemplate temp : templates) {
			if (n < temp.getWeight()) {
				List<ItemInfo> list = temp.getItemList();
				n = CommonUtils.randomInt(list.size());
				return list.get(n);
			}
		}
		return null;
	}

}
